/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.xadrez.ia;

import com.xadrez.Principal;
import com.xadrez.exception.NumeroDeJogadorExcessoException;
import com.xadrez.modelo.Bispo;
import com.xadrez.modelo.Cavalo;
import com.xadrez.modelo.Peao;
import com.xadrez.modelo.Peca;
import com.xadrez.modelo.Posicao;
import com.xadrez.modelo.Rainha;
import com.xadrez.modelo.Rei;
import com.xadrez.modelo.Tabuleiro;
import com.xadrez.modelo.Torre;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author fabricio
 */
public class MiniMaxAB extends IA {

    TabuleiroIA tabuleiro = null;
    private int profundidade;
    private static final int INFINITO = 10000;

    private void inicialize(Tabuleiro tabuleiro) throws NumeroDeJogadorExcessoException {
        this.tabuleiro = new TabuleiroIA(tabuleiro);
    }

    public MiniMaxAB(String nome, int dificuldade) throws NumeroDeJogadorExcessoException {
        super(nome);
        setProfundidade(dificuldade);
    }

// 
    private TabuleiroIA executeMiniMax(TabuleiroIA tabuleiro, int profundidade) throws NumeroDeJogadorExcessoException {
        TabuleiroIA tabuleiroIdeal = new TabuleiroIA(tabuleiro);
        if ((profundidade == 0) || (!tabuleiro.hasJogadas())) {
            return tabuleiro;
        }else if (!tabuleiro.getJogadorDaVez().equals(this)) {
            tabuleiroIdeal.setPeso(INFINITO);
            for (Peca peca : tabuleiro.getPecasJogador(getIdOponente())) {
                for (Posicao posicao : peca.recuperaMovimentosPossiveis()) {
                    TabuleiroIA tabuleiroProximoNivel = (TabuleiroIA) tabuleiro.clone();
                    tabuleiroProximoNivel.Mover(peca, posicao);
                    tabuleiroProximoNivel.setPeso(fstatus(tabuleiroProximoNivel));
                    if (tabuleiroIdeal.getPeso() >= tabuleiroProximoNivel.getPeso()) {
                        tabuleiroIdeal = min(tabuleiroIdeal, executeMiniMax(tabuleiroProximoNivel, profundidade - 1));
                    }
                }
            }
        } else {
            tabuleiroIdeal.setPeso(-INFINITO);
            for (Peca peca : tabuleiro.getPecasJogador(getId())) {
                for (Posicao posicao : peca.recuperaMovimentosPossiveis()) {
                    TabuleiroIA tabuleiroProximoNivel = (TabuleiroIA) tabuleiro.clone();
                    tabuleiroProximoNivel.Mover(peca, posicao);
                    tabuleiroProximoNivel.setPeso(fstatus(tabuleiroProximoNivel));
                    if (tabuleiroIdeal.getPeso() <= tabuleiroProximoNivel.getPeso()) {
                        Jogada jogada = new Jogada(peca, posicao);
                        tabuleiroProximoNivel.setJogada(jogada);
                        tabuleiroIdeal = max(tabuleiroIdeal, executeMiniMax(tabuleiroProximoNivel, profundidade - 1));
                    }
                }
            }

        }
        return tabuleiroIdeal;
    }

    // conveção se positivo jogador ganhado, 0 empate, negativo perdendo
    private int fstatus(TabuleiroIA tabuleiro) {
        int pontos = 0;
        for (Peca peca : tabuleiro.getPecasJogador(getId())) {
            if (peca instanceof Bispo) {
                pontos = pontos + 21;
            } else if (peca instanceof Cavalo) {
                pontos = pontos + 15;
            } else if (peca instanceof Peao) {
                pontos = pontos + 6;
            } else if (peca instanceof Rainha) {
                pontos = pontos + 51;
            } else if (peca instanceof Rei) {
                pontos = pontos + 100;
            } else if (peca instanceof Torre) {
                pontos = pontos + 21;
            }

        }

        for (Peca peca : tabuleiro.getPecasJogador(getIdOponente())) {
            if (peca instanceof Bispo) {
                pontos = pontos - 21;
            } else if (peca instanceof Cavalo) {
                pontos = pontos - 15;
            } else if (peca instanceof Peao) {
                pontos = pontos - 6;
            } else if (peca instanceof Rainha) {
                pontos = pontos - 51;
            } else if (peca instanceof Rei) {
                pontos = pontos - 100;
            } else if (peca instanceof Torre) {
                pontos = pontos - 21;
            }
        }
        return pontos;
    }

    private TabuleiroIA min(TabuleiroIA tabA, TabuleiroIA tabB) {
        int aux = tabA.compareTo(tabB);

        if (aux == 0) {
            aux = random();
        }
        if (aux == -1) {
            return tabA;
        } else {
            return tabB;
        }
    }

    private TabuleiroIA max(TabuleiroIA tabA, TabuleiroIA tabB) {
        int aux = tabA.compareTo(tabB);

        if (aux == 0) {
            aux = random();
        }

        if (aux == 1) {
            return tabA;
        } else {
            return tabB;
        }
    }

    private int random() {
        double aux = Math.random();
        if (aux < 0.5) {
            return -1;
        } else {
            return 1;
        }
    }

    @Override
    public Jogada jogar() {
        TabuleiroIA tab = null;
        System.out.println(getId());
        try {
            inicialize(Principal.getTabuleiro());
            tab = executeMiniMax(this.tabuleiro, this.getProfundidade());
        } catch (NumeroDeJogadorExcessoException ex) {
            Logger.getLogger(MiniMaxAB.class.getName()).log(Level.SEVERE, null, ex);
        }
        Jogada jogada = tab.getJogada();
        jogada.setPeca(Principal.getTabuleiro(jogada.getPeca().getPosicaoNoTabuleiro()));
        try {
            jogada.setPosicaoAntiga(jogada.getPeca().getPosicaoNoTabuleiro());
        } catch (CloneNotSupportedException ex) {
            Logger.getLogger(MiniMax.class.getName()).log(Level.SEVERE, null, ex);
        }
        jogada.executar();
        // promove a peça
        
            if(jogada.getPeca()instanceof Peao)
                if(((Peao) jogada.getPeca()).upar())
                  jogada.setPromocao(true);  
                  
       
        return jogada;
    }

    private int getIdOponente() {
        return getId() % 2 + 1;
    }

    public int getProfundidade() {
        return profundidade;
    }

    public void setProfundidade(int profundidade) {
        this.profundidade = profundidade;
    }
}
